﻿using System;
using System.Collections.Generic;
//using System.Configuration;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Unis.Framework.Core.Log;
using Unis.Framework.ORM.Mapping;
using Unis.ORM.DbSql;
using Unis.ORM.Mapping;
using Unis.Framework.Core.Utility;

namespace Unis.Framework.ORM
{
    public class CacheProxy
    {
        // Fields
        private static readonly object _CFGObj = new object();
        private static readonly object _CSql = new object();
        private static readonly ICacheManager _EntityCache = null;
        private static ICacheItemExpiration[] _EntityCacheSetting;
        private static ICacheManager _MappingCache = null;
        private static object _Obj = new object();
        private static ICacheManager _SqlCache = null;
        private static ICacheManager _XmlCfgFileCache = null;
        private const int ENTITY_CACHE_EXPIRATION_CHECK_INTERVAL = 60;
        private static readonly string ENTITY_CACHE_NAME = "MB.Orm.EntityCache";
        private static readonly string MAPPING_CACHE_NAME = "MB.Orm.MappingCache";
        private static readonly string SQL_CACHE_NAME = "MB.Orm.SqlCache";
        private static readonly string XML_CONFIG_CACHE_NAME = "MB.Orm.XmlCfgFileCache";

        // Methods
        static CacheProxy()
        {
            try
            {
                lock (_Obj)
                {
                    string str = ConfigurationManager.GetAppSetting("EntityCachName");
                    if (string.IsNullOrEmpty(str))
                    {
                        str = ENTITY_CACHE_NAME;
                    }
                    string str2 = ConfigurationManager.GetAppSetting("SqlCachName");
                    if (string.IsNullOrEmpty(str2))
                    {
                        str2 = SQL_CACHE_NAME;
                    }
                    string str3 = ConfigurationManager.GetAppSetting("MappingCachName");
                    if (string.IsNullOrEmpty(str3))
                    {
                        str3 = MAPPING_CACHE_NAME;
                    }
                    string str4 = ConfigurationManager.GetAppSetting("XmlCachName");
                    if (string.IsNullOrEmpty(str4))
                    {
                        str4 = XML_CONFIG_CACHE_NAME;
                    }
                    _EntityCache = CacheFactory.GetCacheManager(str);
                    _SqlCache = CacheFactory.GetCacheManager(str2);
                    _MappingCache = CacheFactory.GetCacheManager(str3);
                    _XmlCfgFileCache = CacheFactory.GetCacheManager(str4);
                }
            }
            catch (Exception exception)
            {
                TraceEx.Write("Unis.ORM.CacheProxy 缓存没有进行相应的配置！" + exception.Message);
            }
        }

        private static string buildKey(object entity)
        {
            Type t = entity.GetType();
            Dictionary<string, FieldPropertyInfo> primaryKeys = AttMappingManager.Instance.GetModelMappingInfo(t).PrimaryKeys;
            object[] keys = new object[primaryKeys.Count];
            int index = 0;
            foreach (string str in primaryKeys.Keys)
            {
                keys[index] = t.GetProperty(str).GetValue(entity, null);
                index++;
            }
            return buildKey(t, keys);
        }

        private static string buildKey(Type t, object[] keys)
        {
            StringBuilder builder = new StringBuilder(t.FullName).Append("@");
            for (int i = 0; i < keys.Length; i++)
            {
                builder.Append(keys[i].ToString()).Append("#");
            }
            return builder.ToString();
        }

        public static void CacheEntity(object entity)
        {
            if (_EntityCache != null)
            {
                string key = buildKey(entity);
                _EntityCache.Add(key, entity);
            }
        }

        public static void CacheEntity(object entity, string key)
        {
            if (_EntityCache != null)
            {
                _EntityCache.Add(key, entity, CacheItemPriority.Normal, null, GetExpirationPolicy());
            }
        }

        public static void CacheMapping(string key, object mapping)
        {
            if (_MappingCache != null)
            {
                _MappingCache.Add(key, mapping);
            }
        }

        public static void CacheSql(string key, SqlString[] sql)
        {
            lock (_CSql)
            {
                if ((_SqlCache != null) && !_SqlCache.Contains(key))
                {
                    _SqlCache.Add(key, sql);
                }
            }
        }

        public static void CacheXmlCfgFile(string key, object mapping)
        {
            lock (_CFGObj)
            {
                if ((_XmlCfgFileCache != null) && !_XmlCfgFileCache.Contains(key))
                {
                    _XmlCfgFileCache.Add(key, mapping);
                }
            }
        }

        public static void ClearEntityCache()
        {
            if (_EntityCache != null)
            {
                _EntityCache.Flush();
            }
        }

        public static bool ContainsCacheMapping(string key)
        {
            if (_MappingCache == null)
            {
                return false;
            }
            return _MappingCache.Contains(key);
        }

        public static bool ContainsEntity(object entity)
        {
            if (_EntityCache == null)
            {
                return false;
            }
            string key = buildKey(entity);
            return _EntityCache.Contains(key);
        }

        public static bool ContainsEntity(Type t, params object[] keys)
        {
            if (_EntityCache == null)
            {
                return false;
            }
            string key = buildKey(t, keys);
            return _EntityCache.Contains(key);
        }

        public static bool ContainsSql(string key)
        {
            if (_SqlCache == null)
            {
                return false;
            }
            return _SqlCache.Contains(key);
        }

        public static bool ContainsXmlCfgFile(string key)
        {
            if (_XmlCfgFileCache == null)
            {
                return false;
            }
            return _XmlCfgFileCache.Contains(key);
        }

        public static object GetCachedEntity(Type t, params object[] keys)
        {
            if (_EntityCache == null)
            {
                return null;
            }
            return _EntityCache.GetData(buildKey(t, keys));
        }

        public static SqlString[] GetCachedSql(string key)
        {
            if (_SqlCache == null)
            {
                return null;
            }
            return (_SqlCache.GetData(key) as SqlString[]);
        }

        public static T GetCacheMapping<T>(string key)
        {
            return (T)_MappingCache.GetData(key);
        }

        public static T GetCacheXmlCfgFile<T>(string key)
        {
            return (T)_XmlCfgFileCache.GetData(key);
        }

        internal static ICacheItemExpiration[] GetExpirationPolicy()
        {
            if (object.Equals(_EntityCacheSetting, null))
            {
                _EntityCacheSetting = (ICacheItemExpiration[])System.Configuration.ConfigurationSettings.GetConfig("MbOrmExpirationPolicy");
            }
            return _EntityCacheSetting;
        }

        public static void RemoveCachedEntity(object entity)
        {
            if (_EntityCache != null)
            {
                string key = buildKey(entity);
                _EntityCache.Remove(key);
            }
        }
    }
}
